#ifndef _LIST_OP_H
#define _LIST_OP_H
// #include <linux/list.h>
#include <linux/rculist.h>
#include <linux/slab.h>

#ifdef DEBUG
#define debug_info(format, ...) printk(format, ##__VA_ARGS__)
#else
#define debug_info(format, ...)
#endif

struct exec_path_entry {
    char*            fullpath;
    struct list_head list;
};

// LIST_HEAD(exec_path_list);
extern struct list_head exec_path_list;
/**
 * ltcs_list_add_entry - add new entry to list tail.
 * @entry: new entry to be added.
 */
static inline void ltcs_list_add_entry(struct exec_path_entry* new_entry)
{
    list_add_tail_rcu(&(new_entry->list), &exec_path_list);
    return;
}

/**
 * ltcs_list_del_entry - delete first entry from list.
 */
static inline struct exec_path_entry* ltcs_list_del_entry(void)
{
    struct exec_path_entry *ptr, *next;
    if (list_empty(&exec_path_list)) return NULL;

    list_for_each_entry_safe(ptr, next, &exec_path_list, list)
    {
        debug_info("del %s from list\n", ptr->fullpath);
        list_del_rcu(&(ptr->list));
        return ptr;
    }
    return NULL;
}

/**
 *  * ltcs_list_del_entry - delete first entry from list.
 *  */
static inline struct exec_path_entry* ltcs_list_pop_entry(void)
{
    struct exec_path_entry *ptr, *next;
    if (list_empty(&exec_path_list)) return NULL;

    list_for_each_entry_safe(ptr, next, &exec_path_list, list)
    {
        debug_info("del %s from list\n", ptr->fullpath);
        // list_del_rcu(&(ptr->list));
        return ptr;
    }
    return NULL;
}

/**
 * ltcs_list_free_entry - free entry's memery
 * @entry: the entry to be free.
 */
static inline void ltcs_list_free_entry(struct exec_path_entry* entry)
{
    kfree(entry->fullpath);
    entry->fullpath = NULL;
    kfree(entry);
    entry = NULL;
    return;
}

/**
 * ltcs_list_del_all - delete all entry from list.
 */
static inline void ltcs_list_del_all(void)
{
    struct exec_path_entry *ptr, *next;
    list_for_each_entry_safe(ptr, next, &exec_path_list, list)
    {
        list_del(&(ptr->list));
        ltcs_list_free_entry(ptr);
    }
    return;
}

/**
 * ltcs_list_print_list - list all entry in list.
 */
static inline void ltcs_list_print_list(void)
{
    struct exec_path_entry* ptr;
    printk("------------------------\n");
    list_for_each_entry(ptr, &exec_path_list, list)
    {
        if (ptr) debug_info("file name:%s\n", ptr->fullpath);
    }
    return;
}

#endif /* _LIST_OP_H */
